[NET] back: Fix packet queuing so that packets are drained if the
authorkfraser@localhost.localdomain <kfraser@localhost.localdomain>
Mon, 23 Oct 2006 10:20:37 +0000 (11:20 +0100)
committerkfraser@localhost.localdomain <kfraser@localhost.localdomain>
Mon, 23 Oct 2006 10:20:37 +0000 (11:20 +0100)
interface is blocked for longer than 500ms. This avoids deadlock
situations where interfaces cannot be destroyed because some other
dormant interface is holding resources.

Signed-off-by: Christopher Clark <christopher.clark@cl.cam.ac.uk>
Signed-off-by: Keir Fraser <keir@xensource.com>
linux-2.6-xen-sparse/drivers/xen/netback/common.h
linux-2.6-xen-sparse/drivers/xen/netback/interface.c
linux-2.6-xen-sparse/drivers/xen/netback/netback.c
linux-2.6-xen-sparse/drivers/xen/netback/xenbus.c

index 34dd998663d52a4c6499fc2ea078c7a92a8ce0ed..367c008d3bb4eed46b981ed4384e83c6af7b8101 100644 (file)
@@ -92,6 +92,9 @@ typedef struct netif_st {
        unsigned long   remaining_credit;
        struct timer_list credit_timeout;
 
+       /* Enforce draining of the transmit queue. */
+       struct timer_list tx_queue_timeout;
+
        /* Miscellaneous private stuff. */
        struct list_head list;  /* scheduling list */
        atomic_t         refcnt;
@@ -119,6 +122,8 @@ int netif_map(netif_t *netif, unsigned long tx_ring_ref,
 
 void netif_xenbus_init(void);
 
+#define netif_schedulable(dev) (netif_running(dev) && netif_carrier_ok(dev))
+
 void netif_schedule_work(netif_t *netif);
 void netif_deschedule_work(netif_t *netif);
 
index 78aa4cd8c557e7601161c264a491d7fe38d9c51b..c56013945b95001d94849c80cac95e6a1939a2cf 100644 (file)
  * For example, consider a packet that holds onto resources belonging to the
  * guest for which it is queued (e.g., packet received on vif1.0, destined for
  * vif1.1 which is not activated in the guest): in this situation the guest
- * will never be destroyed, unless vif1.1 is taken down (which flushes the
- * 'tx_queue').
- * 
- * Only set this parameter to non-zero value if you know what you are doing!
+ * will never be destroyed, unless vif1.1 is taken down. To avoid this, we
+ * run a timer (tx_queue_timeout) to drain the queue when the interface is
+ * blocked.
  */
-static unsigned long netbk_queue_length = 0;
+static unsigned long netbk_queue_length = 32;
 module_param_named(queue_length, netbk_queue_length, ulong, 0);
 
 static void __netif_up(netif_t *netif)
@@ -62,7 +61,6 @@ static void __netif_down(netif_t *netif)
 {
        disable_irq(netif->irq);
        netif_deschedule_work(netif);
-       del_timer_sync(&netif->credit_timeout);
 }
 
 static int net_open(struct net_device *dev)
@@ -153,8 +151,11 @@ netif_t *netif_alloc(domid_t domid, unsigned int handle)
        netif->credit_bytes = netif->remaining_credit = ~0UL;
        netif->credit_usec  = 0UL;
        init_timer(&netif->credit_timeout);
+       /* Initialize 'expires' now: it's used to track the credit window. */
        netif->credit_timeout.expires = jiffies;
 
+       init_timer(&netif->tx_queue_timeout);
+
        dev->hard_start_xmit = netif_be_start_xmit;
        dev->get_stats       = netif_be_get_stats;
        dev->open            = net_open;
@@ -319,11 +320,23 @@ err_rx:
        return err;
 }
 
-static void netif_free(netif_t *netif)
+void netif_disconnect(netif_t *netif)
 {
+       if (netif_carrier_ok(netif->dev)) {
+               rtnl_lock();
+               netif_carrier_off(netif->dev);
+               if (netif_running(netif->dev))
+                       __netif_down(netif);
+               rtnl_unlock();
+               netif_put(netif);
+       }
+
        atomic_dec(&netif->refcnt);
        wait_event(netif->waiting_to_free, atomic_read(&netif->refcnt) == 0);
 
+       del_timer_sync(&netif->credit_timeout);
+       del_timer_sync(&netif->tx_queue_timeout);
+
        if (netif->irq)
                unbind_from_irqhandler(netif->irq, netif);
        
@@ -337,16 +350,3 @@ static void netif_free(netif_t *netif)
 
        free_netdev(netif->dev);
 }
-
-void netif_disconnect(netif_t *netif)
-{
-       if (netif_carrier_ok(netif->dev)) {
-               rtnl_lock();
-               netif_carrier_off(netif->dev);
-               if (netif_running(netif->dev))
-                       __netif_down(netif);
-               rtnl_unlock();
-               netif_put(netif);
-       }
-       netif_free(netif);
-}
index 08c075ac274b3547aab3a7917e8762d0893e75bc..5706322a8f03c6ec12ca0be4472425b0689c4da3 100644 (file)
@@ -264,6 +264,13 @@ static inline int netbk_queue_full(netif_t *netif)
               ((netif->rx.rsp_prod_pvt + NET_RX_RING_SIZE - peek) < needed);
 }
 
+static void tx_queue_callback(unsigned long data)
+{
+       netif_t *netif = (netif_t *)data;
+       if (netif_schedulable(netif->dev))
+               netif_wake_queue(netif->dev);
+}
+
 int netif_be_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
        netif_t *netif = netdev_priv(dev);
@@ -271,20 +278,13 @@ int netif_be_start_xmit(struct sk_buff *skb, struct net_device *dev)
        BUG_ON(skb->dev != dev);
 
        /* Drop the packet if the target domain has no receive buffers. */
-       if (unlikely(!netif_running(dev) || !netif_carrier_ok(dev)))
+       if (unlikely(!netif_schedulable(dev) || netbk_queue_full(netif)))
                goto drop;
 
-       if (unlikely(netbk_queue_full(netif))) {
-               /* Not a BUG_ON() -- misbehaving netfront can trigger this. */
-               if (netbk_can_queue(dev))
-                       DPRINTK("Queue full but not stopped!\n");
-               goto drop;
-       }
-
-       /* Copy the packet here if it's destined for a flipping
-          interface but isn't flippable (e.g. extra references to
-          data)
-       */
+       /*
+        * Copy the packet here if it's destined for a flipping interface
+        * but isn't flippable (e.g. extra references to data).
+        */
        if (!netif->copying_receiver && !is_flippable_skb(skb)) {
                struct sk_buff *nskb = netbk_copy_skb(skb);
                if ( unlikely(nskb == NULL) )
@@ -305,8 +305,19 @@ int netif_be_start_xmit(struct sk_buff *skb, struct net_device *dev)
                netif->rx.sring->req_event = netif->rx_req_cons_peek +
                        netbk_max_required_rx_slots(netif);
                mb(); /* request notification /then/ check & stop the queue */
-               if (netbk_queue_full(netif))
+               if (netbk_queue_full(netif)) {
                        netif_stop_queue(dev);
+                       /*
+                        * Schedule 500ms timeout to restart the queue, thus
+                        * ensuring that an inactive queue will be drained.
+                        * Packets will be immediately be dropped until more
+                        * receive buffers become available (see
+                        * netbk_queue_full() check above).
+                        */
+                       netif->tx_queue_timeout.data = (unsigned long)netif;
+                       netif->tx_queue_timeout.function = tx_queue_callback;
+                       __mod_timer(&netif->tx_queue_timeout, jiffies + HZ/2);
+               }
        }
 
        skb_queue_tail(&rx_queue, skb);
@@ -706,6 +717,7 @@ static void net_rx_action(unsigned long unused)
                }
 
                if (netif_queue_stopped(netif->dev) &&
+                   netif_schedulable(netif->dev) &&
                    !netbk_queue_full(netif))
                        netif_wake_queue(netif->dev);
 
@@ -763,8 +775,7 @@ static void add_to_net_schedule_list_tail(netif_t *netif)
 
        spin_lock_irq(&net_schedule_list_lock);
        if (!__on_net_schedule_list(netif) &&
-           likely(netif_running(netif->dev) &&
-                  netif_carrier_ok(netif->dev))) {
+           likely(netif_schedulable(netif->dev))) {
                list_add_tail(&netif->list, &net_schedule_list);
                netif_get(netif);
        }
@@ -1358,7 +1369,7 @@ irqreturn_t netif_be_int(int irq, void *dev_id, struct pt_regs *regs)
        add_to_net_schedule_list_tail(netif);
        maybe_schedule_tx_action();
 
-       if (netif_queue_stopped(netif->dev) && !netbk_queue_full(netif))
+       if (netif_schedulable(netif->dev) && !netbk_queue_full(netif))
                netif_wake_queue(netif->dev);
 
        return IRQ_HANDLED;
index c61821c8f93f54e29ea4e0ac28ef3b9f04333384..b81042d701db0f1094ffd664ae890652703d28e5 100644 (file)
@@ -328,7 +328,7 @@ static void connect(struct backend_info *be)
 
        /* May not get a kick from the frontend, so start the tx_queue now. */
        if (!netbk_can_queue(be->netif->dev))
-               netif_start_queue(be->netif->dev);
+               netif_wake_queue(be->netif->dev);
 }